﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sinacor.OMM.Configuration;
using Sinacor.OMM.Configuration.Receptor;
using System.IO;
using System.Configuration;
using Sinacor.OMM.Configuration.OrderBovespaSystem;
using System.Threading;
using System.Management;
using System.Diagnostics;
using Sinacor.OMM.Logging;
using PSE.Framework.Threading;

namespace Sinacor.OMM.Receptor.CommunicationChannel
{
    /// <summary>
    /// Manage the receptor configuration
    /// </summary>
    public class ReceptorConfigurationManager
    {

        static string _configFile;
        static ReceptorConfiguration _configurationInstance;
        static AuthenticationConfiguration _authentication;
        static OrderBovespaSystemConfiguration _orderBovespaSystemInformation;
        static Thread messageReaderThread;
        private static bool _shouldStopRefreshing = false;
        private static object _authenticationLock = new object();

        /// <summary>
        /// Authentication configuration
        /// </summary>
        public static AuthenticationConfiguration Authentication
        {
            get
            {
                try
                {
                    lock (_authenticationLock)
                    {
                        if (_authentication == null)
                        {
                            Int32 companyId;

                            _authentication = new AuthenticationConfiguration();

                            if (string.IsNullOrEmpty(_configFile))
                                _configFile = Path.Combine(Path.GetDirectoryName(System.Configuration.ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath), "Sinacor.OMM.Receptor.exe");

                            System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(_configFile);

                            if (config == null)
                                throw new ConfigurationErrorsException(string.Format("Arquivo de configuração '{0}'.config não encontrado.", _configFile));

                            if (!Int32.TryParse(config.AppSettings.Settings["companyId"].Value, out companyId))
                                throw new ConfigurationErrorsException(String.Format("Código da empresa não encontrado, impossível realizar a conexão com o banco de dados do Sinacor." + System.Environment.NewLine +
                                                                                     "Verificar a tag appSettings do arquivo {0}.config. Verificar a existência da chave  <add key='companyId' value='' />.", _configFile));

                            _authentication.CompanyId = companyId;

                            if (config.AppSettings.Settings["user"] != null)
                                _authentication.User = config.AppSettings.Settings["user"].Value;

                            if (config.AppSettings.Settings["password"] != null)
                                _authentication.Password = config.AppSettings.Settings["password"].Value;
                        }
                    }
                }
                catch (Exception ex)
                {
                    EventLog.WriteEntry("Receptor Service Configuration", ex.ToString(), EventLogEntryType.Error);
                    throw ex;
                }

                return _authentication;
            }
        }

        /// <summary>
        /// Order Bovespa System Information
        /// </summary>
        public static OrderBovespaSystemConfiguration OrderBovespaSystemInformation
        {
            get
            {
                try
                {
                    if (_orderBovespaSystemInformation == null)
                        BuildOrderBovespaSystemInformation();
                }
                catch (Exception ex)
                {
                    EventLog.WriteEntry(LogSources.ReceptorService, string.Concat(ex.Message, " ", ex.StackTrace), EventLogEntryType.Error);
                }

                return _orderBovespaSystemInformation;
            }
        }

        /// <summary>
        /// Recupera as configurações do receptor
        /// </summary>
        /// <returns></returns>
        public static ReceptorConfiguration ReceptorConfiguration
        {
            get
            {
                try
                {
                    if (_configurationInstance == null)
                        BuildReceptorConfiguration();
                }
                catch (Exception ex)
                {
                    EventLog.WriteEntry("Receptor Service Configuration", ex.ToString(), EventLogEntryType.Error);
                    throw ex;
                }

                return _configurationInstance;
            }
        }

        /// <summary>
        /// Build receptor configuration
        /// </summary>
        private static void BuildReceptorConfiguration()
        {
            _configurationInstance = new OMM.Configuration.Receptor.ReceptorConfigurationReader(Authentication.CompanyId).GetConfiguration();

            if (_configurationInstance == null)
            {
                throw new ConfigurationErrorsException(@"Não existem canais de comunicação cadastrados para o Receptor." + System.Environment.NewLine +
                                                        "Verificar as configurações do receptor na tabela TBOCNFG_RCPT.");
            }
            else
            {
                lock (_configurationInstance)
                {
                    foreach (Configuration.Receptor.CommunicationChannel _config in _configurationInstance.CommunicationChannels)
                    {
                        CheckCommunicationChannelConfiguration(_config);
                        _config.MacAddress = GetMacAddress();
                    }
                }
            }
        }

        /// <summary>
        /// Build order Bovespa system configuration
        /// </summary>
        private static void BuildOrderBovespaSystemInformation()
        {
            try
            {
                _orderBovespaSystemInformation =
                    new OrderBovespaSystemConfigurationReader(Authentication.CompanyId).GetOrderBovespaSystemInformation();
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry("Receptor Service Configuration: BuildOrderBovespaSystemInformation()", ex.ToString(), EventLogEntryType.Error);
                _orderBovespaSystemInformation = new OrderBovespaSystemConfiguration();
                _orderBovespaSystemInformation.State = SystemState.Closed;
            }
        }

        /// <summary>
        /// Start refresh
        /// </summary>
        public static void StartRefresh()
        {
            _shouldStopRefreshing = false;
            messageReaderThread = new Thread(new ThreadStart(UpdateConfiguration));
            messageReaderThread.Start();
        }

        /// <summary>
        /// Stop refresh
        /// </summary>
        public static void StopRefresh()
        {
            _shouldStopRefreshing = true;
        }

        /// <summary>
        /// Update the configuration
        /// </summary>
        private static void UpdateConfiguration()
        {
            while (!_shouldStopRefreshing)
            {
                Sleeper.Sleep(60000, () => !_shouldStopRefreshing);
                BuildOrderBovespaSystemInformation();
            }
        }

        /// <summary>
        /// Get de mac address of machine where the HFT process is installed
        /// </summary>
        /// <returns></returns>
        private static string GetMacAddress()
        {
            ManagementClass management = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection managementObjects = management.GetInstances();
            string macAddress = string.Empty;

            foreach (ManagementObject item in managementObjects)
            {
                if ((bool)item["IPEnabled"] == true)
                {
                    macAddress = item["MacAddress"].ToString().Replace(":", "").Trim();
                }

                item.Dispose();
            }

            management.Dispose();
            managementObjects.Dispose();

            return macAddress;
        }

        /// <summary>
        /// Check the communication channel configuration
        /// </summary>
        private static void CheckCommunicationChannelConfiguration(Configuration.Receptor.CommunicationChannel _communicationChannel)
        {
            //
            if (String.IsNullOrEmpty(_communicationChannel.User))
            {
                EventLog.WriteEntry("Receptor Service Configuration", string.Format(@"Usuário para conexão do canal de comunicação {0} não foi encontrado." + System.Environment.NewLine +
                                                                                     "Verificar a coluna NOME_USUA_CONX da tabela TBOCNFG_RCPT.", _communicationChannel.Id), EventLogEntryType.Error);
            }

            //
            if (String.IsNullOrEmpty(_communicationChannel.Password))
            {
                EventLog.WriteEntry("Receptor Service Configuration", string.Format(@"Senha para conexão do canal de comunicação {0} não foi encontrado." + System.Environment.NewLine +
                                                                                     "Verificar a coluna TXT_SENH_USUA_CONX da tabela TBOCNFG_RCPT.", _communicationChannel.Id), EventLogEntryType.Warning);
            }

            //
            if (String.IsNullOrEmpty(_communicationChannel.Employee))
            {
                EventLog.WriteEntry("Receptor Service Configuration", string.Format(@"Funcionário para conexão do canal de comunicação {0} não foi encontrado." + System.Environment.NewLine +
                                                                                     "Verificar a coluna NOME_FUNC_SESS da tabela TBOCNFG_RCPT.", _communicationChannel.Id), EventLogEntryType.Warning);
            }

            //
            if (_communicationChannel.MessageMainRepository == null)
            {
                EventLog.WriteEntry("Receptor Service Configuration", string.Format(@"Repositório principal de mensagens do canal de comunicação {0} não foi encontrado." + System.Environment.NewLine +
                                                                                     "Verificar a coluna COD_REPRIO_PRIN da tabela TBOCNFG_RCPT.", _communicationChannel.Id), EventLogEntryType.Error);
            }

            //
            if (_communicationChannel.SystemMessageRepository == null)
            {
                EventLog.WriteEntry("Receptor Service Configuration", string.Format(@"Repositório de mensagens enviadas pelo Roteador para o canal de comunicação {0} não foi encontrado." + System.Environment.NewLine +
                                                                                     "Verificar a coluna COD_REPRIO_MSG_SIST da tabela TBOCNFG_RCPT.", _communicationChannel.Id), EventLogEntryType.Error);
            }

            //
            if (String.IsNullOrEmpty(_communicationChannel.ControllerFilePath))
            {
                EventLog.WriteEntry("Receptor Service Configuration", string.Format(@"Diretório do arquivo de controle do canal de comunicação {0} não foi encontrado." + System.Environment.NewLine +
                                                                                     "Verificar a coluna NOME_DRTO_ARQ_CTRL da tabela TBOCNFG_RCPT.", _communicationChannel.Id), EventLogEntryType.Warning);
            }
        }

    }
}
